/**
 * 路径类
 */

// todo: 
// 1. 获取沿路径上的旋转信息;
// 2. 沿路径生成物理模型（路）;

import * as THREE from "./three.js/build/three.module.js";
import { AmmoLib } from "./A3Class.js";
import A3Actor from "./A3Actor.js";
import { addAxesHelper } from "./A3Common.js";

class A3Path extends A3Actor {
  name = "path"

  positions = [];
  curveType = "chordal"; // ["chordal", "centripetal", "catmullrom"]
  ARC_SEGMENTS = 200;

  pointSize = .5;
  pointColor = 0x1982cc;

  isClosed = true;

  constructor( radius=10, radialSegments=8 ) {
    super();

    // 不小于2
    radialSegments = radialSegments < 2 ? 8 : radialSegments ;
    radius = radius <= 0 ? 10 : radius;

    this.updatePoints( radius, radialSegments );
  }

  updatePoints( radius, radialSegments ) {

    const tmpPos = new THREE.Vector3();
    const positions = [];
    const pointMeshes = [];
    const pointSize = this.pointSize;
    const pointColor = this.pointColor;

    const path = new THREE.Group();

    const pointGeometry = new THREE.BoxGeometry( pointSize, pointSize, pointSize );
    const pointMaterial = new THREE.MeshBasicMaterial( { color: pointColor } );

    for( var i = 0; i < radialSegments; i ++ ) {

      const ir = ( i / radialSegments ) * Math.PI * 2;
      const height = Math.random() * radius;

      tmpPos.set( 
        Math.sin( ir ) * radius, 
        height, 
        Math.cos( ir ) * radius );

      positions.push( tmpPos.clone() );

      const pointMesh = new THREE.Mesh( pointGeometry, pointMaterial );
      addAxesHelper( pointMesh, pointSize * 1.5 );

      pointMesh.position.copy( tmpPos );
      pointMeshes.push( pointMesh );
            
      path.add( pointMesh );

      // 计算Z方向旋转角度
      if( i > 1 ){
        // const d = positions[i-1].distanceTo(positions[i]);
        // const rz = Math.asin( (positions[i].y - positions[i-1].y) / d );
        
        const euler = new THREE.Euler(- Math.atan( height/ radius ), ir, 0 );
      
        // pointMesh.quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), ir );
        pointMeshes[i-1].quaternion.setFromEuler( euler );
      }
      
      if ( i === radialSegments - 1 ){
        // const d = positions[i].distanceTo(positions[0]);
        // const rz = Math.asin( (positions[0].y - positions[i].y) / d );
        
        const euler = new THREE.Euler(- Math.atan( height/ radius ), ir, 0 );
      
        // pointMesh.quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), ir );
        pointMeshes[i].quaternion.setFromEuler( euler );
      }

    }

    const curve = new THREE.CatmullRomCurve3( positions );
    curve.curveType = this.curveType;
    curve.closed = this.isClosed;

    const points = curve.getPoints( this.ARC_SEGMENTS );
    const geometry = new THREE.BufferGeometry().setFromPoints( points );
    geometry.computeVertexNormals();
    // geometry.setAttribute( 'position', 
    //   new THREE.BufferAttribute( new Float32Array( this.ARC_SEGMENTS * 3 ), 3 ) );

    curve.mesh = new THREE.Line( geometry.clone(), new THREE.LineBasicMaterial( {
      color: 0xff0000,
      // opacity: 0.35
    } ) );

    path.add( curve.mesh );

    this.curve = curve;
    this.threeObject = path;
    this.positions = positions;

  }

  getPointAt( index ) {

    const point = this.curve.getPointAt( index );
    point.applyQuaternion( this.quaternion );
    point.add(this.position);

    return point;

  }

  getQuaternionAt( index ) {

    const euler = new THREE.Euler( 0, index * Math.PI * 2, 0 );
    
    return new THREE.Quaternion().setFromEuler( euler );

  }

}

export default A3Path;